<template>
  <div class="page">
    <NodePanel @addNode="addNode" />
    <div id="container"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import G6 from "@antv/g6";
import NodePanel from "./component/NodePanel/NodePanel.vue";

const graphData = {
  // 点集
  nodes: [
    {
      id: "node1",
      label: "node1",
      x: 300,
      y: 200,
    },
    {
      id: "node2",
      label: "node2",
      x: 600,
      y: 200,
    },
  ],
  // 边集
  edges: [
    // 表示一条从 node1 节点连接到 node2 节点的边
    {
      source: "node1",
      target: "node2",
    },
  ],
};

let graph = null;

function initGraph() {
  const width = document.getElementById("container").scrollWidth;
  const height = document.getElementById("container").scrollHeight || 1000;

  graph = new G6.Graph({
    container: "container",
    width,
    height,
    fitCenter: true, //转换图形以对齐画布的中心
    modes: {
      default: [
        "drag-canvas", // 允许拖拽画布
        "zoom-canvas", // 允许缩放画布
        "click-select", // 允许点击选中元素
        "drag-node", // 允许拖拽节点
        "create-edge", // 启用创建边的行为
      ],
    },
    defaultNode: {
      type: "circle",
      size: [40],
      // 设置文本位置
      labelCfg: {
        position: "bottom",
      },
      /* 四个链接点的配置 */
      linkPoints: {
        top: true,
        right: true,
        bottom: true,
        left: true,
      },
      /* 图标配置 */
      icon: {
        /* whether show the icon, false by default */
        show: true,
        /* icon's img address, string type */
        // img: "https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg",
        /* icon's size, 20 * 20 by default: */
        //   width: 40,
        //   height: 40
      },
    },

    // G6边的交互样式
    edgeStateStyles: {
      hover: {
        stroke: "red",
        lineWidth: 2,
      },
    },
    // 节点交互样式
    nodeStateStyles: {
      // node style of active state
      active: {
        fillOpacity: 0.8,
      },
      // node style of selected state
      selected: {
        lineWidth: 5,
      },
    },
  });

  // 将初始数据和图表渲染到画布上
  graph.data(graphData);
  graph.render();

  // 监听边的 mouseenter 和 mouseleave 事件，触发 hover 状态
  graph.on("edge:mouseenter", (e) => {
    const edge = e.item;
    graph.setItemState(edge, "hover", true);
  });

  graph.on("edge:mouseleave", (e) => {
    const edge = e.item;
    graph.setItemState(edge, "hover", false);
  });

  // 启用点击创建边功能
  graph.on("node:click", (e) => {
    const node = e.item;
    const selectedNodeId = node.getID();

    // 如果之前已经选中了一个节点，那么创建一条边
    if (graph.selectedNode) {
      const sourceNodeId = graph.selectedNode.getID();
      graph.addItem("edge", {
        id: "edge" + Math.random(),
        source: sourceNodeId,
        target: selectedNodeId,
        // label:"边的标签"，显示在边的中间
        style: {
          stroke: "blue",
          lineWidth: 2,
          // endArrow: true,       // 是否显示箭头
          // curveness: 0.2          // 设置边的弯曲度
        },
      });
      // 清除之前选中的节点
      graph.selectedNode = null;
    } else {
      // 如果没有选中节点，则标记当前节点为选中状态
      graph.selectedNode = node;
    }
  });

  // 删除节点功能
  graph.on("node:contextmenu", (e) => {
    e.preventDefault(); // 阻止默认右键菜单
    const node = e.item;
    const nodeId = node.getModel().id;

    const confirmDelete = confirm(
      `你确定要删除这个节点及关联的边吗 ${nodeId}?`
    );
    if (confirmDelete) {
      graph.removeItem(node, true); // 删除节点及其关联的边
    }
  });

  // 删除边功能
  graph.on("edge:contextmenu", (e) => {
    e.preventDefault(); // 阻止默认右键菜单
    const edge = e.item; // 获取点击的边
    const edgeId = edge.getModel().id; // 获取边的 id
    const confirmDelete = confirm(`你确定要删除这条边吗 ${edgeId}?`);
    if (confirmDelete) {
      graph.removeItem(edge); // 删除边
    }
  });
}

// 添加节点
function addNode(data) {
  const point = graph.getPointByClient(data.x, data.y);
  const model = {
    id: "node" + Math.random(),
    label: data.type, //节点的文本标签，通常显示在节点中心
    type: "circle", // 图片类型的节点
    x: point.x,
    y: point.y,
    // 节点的样式，如颜色、边框、大小等。
    size: 40,
  };

  /**
   * 向画布添加节点，使用G6的addItem方法
   * 第一个参数:节点类型,node是节点，edge是一条边
   * 第二个参数：节点数据，
   * 第三个参数：是否需要重渲染，决定是否禁用该操作的事件触发。false会更新，true不会
   *  */
  graph.addItem("node", model, false);
}

onMounted(() => {
  initGraph();
});
</script>

<style lang="scss" scoped>
.page {
  flex: 1;
  height: 100%;
  overflow: hidden;
  position: relative;
}

#graph {
  width: 100%;
  height: 100%;
}
</style>
